<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    class EventEmitter {
  constructor() {
    this.events = {};
  }

  // 订阅事件
  subscribe(eventName, callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(callback);
  }

  // 发布事件
  publish(eventName, data) {
    const eventCallbacks = this.events[eventName];
    if (eventCallbacks) {
      eventCallbacks.forEach(callback => callback(data));
    }
  }

  // 取消订阅
  unsubscribe(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName] = this.events[eventName].filter(cb => cb !== callback);
    }
  }

  // 只订阅一次
  once(eventName, callback) {
    const onceWrapper = (...args) => {
      callback(...args);
      this.unsubscribe(eventName, onceWrapper);
    };
     this.subscribe(eventName, onceWrapper);
  }
}

// 使用示例
const eventEmitter = new EventEmitter();

// 订阅事件
const unsubscribe = eventEmitter.subscribe('userLoggedIn', data => {
  console.log('User logged in:', data);
});

// 发布事件
eventEmitter.publish('userLoggedIn', { id: 1, name: 'John Doe' });



// 只订阅一次
eventEmitter.once('oneTimeEvent', data => {
  console.log('This will only be called once:', data);
});

eventEmitter.publish('oneTimeEvent', { message: 'Hello' });
eventEmitter.publish('oneTimeEvent', { message: 'This wont be logged' });

  </script>
</body>
</html>